1 // ----------------------------------------------------------------------------
2 // <copyright file=
"PhotonEditor.cs" company="Exit Games GmbH">
3 // PhotonNetwork Framework
for Unity - Copyright (C) 2011 Exit Games GmbH
4 // </copyright>
5 // <summary>
6 // MenuItems and
in-Editor scripts for PhotonNetwork.
7 // </summary>
8 // <author>developer@exitgames.com</author>
9 // ----------------------------------------------------------------------------

10 using
System;
11 using
System.Collections.Generic;
12 using
System.IO;
13 using
System.Reflection;
14 using
ExitGames.Client.Photon;
15 using
UnityEditor;
16 using
UnityEditorInternal;
17 using
UnityEngine;
18
19
20 public
class Text
21 {
22     
public string WindowTitle = "PUN Wizard";
23     
public string SetupWizardWarningTitle = "Warning";
24     
public string SetupWizardWarningMessage = "You have not yet run the Photon setup wizard! Your game won't be able to connect. See Windows -> Photon Unity Networking.";
25     
public string MainMenuButton = "Main Menu";
26     
public string ConnectButton = "Connect to Photon Cloud";
27     
public string UsePhotonLabel = "Using the Photon Cloud is free for development. If you don't have an account yet, enter your email and register.";
28     
public string SendButton = "Send";
29     
public string EmailLabel = "Email:";
30     
public string SignedUpAlreadyLabel = "I am already signed up. Let me enter my AppId.";
31     
public string SetupButton = "Setup";
32     
public string RegisterByWebsiteLabel = "I want to register by a website.";
33     
public string AccountWebsiteButton = "Open account website";
34     
public string SelfHostLabel = "I want to host my own server. Let me set it up.";
35     
public string SelfHostSettingsButton = "Open self-hosting settings";
36     
public string MobileExportNoteLabel = "Build for mobiles impossible. Get PUN+ or Unity Pro for mobile.";
37     
public string MobilePunPlusExportNoteLabel = "PUN+ available. Using native sockets for iOS/Android.";
38     
public string EmailInUseLabel = "The provided e-mail-address has already been registered.";
39     
public string KnownAppIdLabel = "Ah, I know my Application ID. Get me to setup.";
40     
public string SeeMyAccountLabel = "Mh, see my account page";
41     
public string SelfHostSettingButton = "Open self-hosting settings";
42     
public string OopsLabel = "Oops!";
43     
public string SeeMyAccountPage = "";
44     
public string CancelButton = "Cancel";
45     
public string PhotonCloudConnect = "Connect to Photon Cloud";
46     
public string SetupOwnHostLabel = "Setup own Photon Host";
47     
public string PUNWizardLabel = "Photon Unity Networking (PUN) Wizard";
48     
public string SettingsButton = "Settings";
49     
public string SetupServerCloudLabel = "Setup wizard for setting up your own server or the cloud.";
50     
public string WarningPhotonDisconnect = "";
51     
public string ConverterLabel = "Converter";
52     
public string StartButton = "Start";
53     
public string UNtoPUNLabel = "Converts pure Unity Networking to Photon Unity Networking.";
54     
public string SettingsFileLabel = "Settings File";
55     
public string LocateSettingsButton = "Locate settings asset";
56     
public string SettingsHighlightLabel = "Highlights the used photon settings file in the project.";
57     
public string DocumentationLabel = "Documentation";
58     
public string OpenPDFText = "Open PDF";
59     
public string OpenPDFTooltip = "Opens the local documentation pdf.";
60     
public string OpenDevNetText = "Open DevNet";
61     
public string OpenDevNetTooltip = "Online documentation for Photon.";
62     
public string OpenCloudDashboardText = "Open Cloud Dashboard";
63     
public string OpenCloudDashboardTooltip = "Review Cloud App information and statistics.";
64     
public string OpenForumText = "Open Forum";
65     
public string OpenForumTooltip = "Online support for Photon.";
66     
public string QuestionsLabel = "Questions? Need help or want to give us feedback? You are most welcome!";
67     
public string SeeForumButton = "See the Photon Forum";
68     
public string OpenDashboardButton = "Open Dashboard (web)";
69     
public string AppIdLabel = "Your AppId";
70     
public string AppIdInfoLabel = "The AppId a Guid that identifies your game in the Photon Cloud. Find it on your dashboard page.";
71     
public string CloudRegionLabel = "Cloud Region";
72     
public string RegionalServersInfo = "Photon Cloud has regional servers. Picking one near your customers improves ping times. You could use more than one but this setup does not support it.";
73     
public string SaveButton = "Save";
74     
public string SettingsSavedTitle = "Success";
75     
public string SettingsSavedMessage = "Saved your settings.\nConnectUsingSettings() will use the settings file.";
76     
public string OkButton = "Ok";
77     
public string SeeMyAccountPageButton = "Mh, see my account page";
78     
public string SetupOwnServerLabel = "Running my app in the cloud was fun but...\nLet me setup my own Photon server.";
79     
public string OwnHostCloudCompareLabel = "I am not quite sure how 'my own host' compares to 'cloud'.";
80     
public string ComparisonPageButton = "See comparison page";
81     
public string YourPhotonServerLabel = "Your Photon Server";
82     
public string AddressIPLabel = "Address/ip:";
83     
public string PortLabel = "Port:";
84     
public string LicensesLabel = "Licenses";
85     
public string LicenseDownloadText = "Free License Download";
86     
public string LicenseDownloadTooltip = "Get your free license for up to 100 concurrent players.";
87     
public string TryPhotonAppLabel = "Running my own server is too much hassle..\nI want to give Photon's free app a try.";
88     
public string GetCloudAppButton = "Get the free cloud app";
89     
public string ConnectionTitle = "Connecting";
90     
public string ConnectionInfo = "Connecting to the account service..";
91     
public string ErrorTextTitle = "Error";
92     
public string ServerSettingsMissingLabel = "Photon Unity Networking (PUN) is missing the 'ServerSettings' script. Re-import PUN to fix this.";
93     
public string MoreThanOneLabel = "There are more than one ";
94     
public string FilesInResourceFolderLabel = " files in 'Resources' folder. Check your project to keep only one. Using: ";
95     
public string IncorrectRPCListTitle = "Warning: RPC-list becoming incompatible!";
96     
public string IncorrectRPCListLabel = "Your project's RPC-list is full, so we can't add some RPCs just compiled.\n\nBy removing outdated RPCs, the list will be long enough but incompatible with older client builds!\n\nMake sure you change the game version where you use PhotonNetwork.ConnectUsingSettings().";
97     
public string RemoveOutdatedRPCsLabel = "Remove outdated RPCs";
98     
public string FullRPCListTitle = "Warning: RPC-list is full!";
99     
public string FullRPCListLabel = "Your project's RPC-list is too long for PUN.\n\nYou can change PUN's source to use short-typed RPC index. Look for comments 'LIMITS RPC COUNT'\n\nAlternatively, remove some RPC methods (use more parameters per RPC maybe).\n\nAfter a RPC-list refresh, make sure you change the game version where you use PhotonNetwork.ConnectUsingSettings().";
100     
public string SkipRPCListUpdateLabel = "Skip RPC-list update";
101     
public string PUNNameReplaceTitle = "Warning: RPC-list Compatibility";
102     
public string PUNNameReplaceLabel = "PUN replaces RPC names with numbers by using the RPC-list. All clients must use the same list for that.\n\nClearing it most likely makes your client incompatible with previous versions! Change your game version or make sure the RPC-list matches other clients.";
103     
public string RPCListCleared = "Clear RPC-list";
104     
public string ServerSettingsCleanedWarning = "Cleared the PhotonServerSettings.RpcList! This makes new builds incompatible with older ones. Better change game version in PhotonNetwork.ConnectUsingSettings().";
105     
public string BestRegionLabel = "best";
106 }

107
108
109 [InitializeOnLoad]

110 public
class PhotonEditor : EditorWindow
111 {
112     
public static Text CurrentLang = new Text();
113
114     
protected static AccountService.Origin RegisterOrigin = AccountService.Origin.Pun;
115
116     
protected Vector2 scrollPos = Vector2.zero;
117
118     
protected static string DocumentationLocation = "Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf";
119
120     
protected static string UrlFreeLicense = "https://www.exitgames.com/en/OnPremise/Dashboard";
121
122     
protected static string UrlDevNet = "http://doc.exitgames.com/en/pun/current/getting-started";
123
124     
protected static string UrlForum = "http://forum.exitgames.com";
125
126     
protected static string UrlCompare = "http://doc.exitgames.com/en/realtime/current/getting-started/onpremise-or-saas";
127
128     
protected static string UrlHowToSetup = "http://doc.exitgames.com/en/onpremise/current/getting-started/photon-server-in-5min";
129
130     
protected static string UrlAppIDExplained = "http://doc.exitgames.com/en/realtime/current/getting-started/obtain-your-app-id";
131
132     
protected static string UrlAccountPage = "https://www.exitgames.com/Account/SignIn?email="; // opened in browser
133
134     
protected static string UrlCloudDashboard = "https://cloud.exitgames.com/Dashboard?email=";
135
136
137     
private enum GUIState
138     {
139         Uninitialized,
140
141         Main,
142
143         Setup
144     }
145
146     
private enum PhotonSetupStates
147     {
148         RegisterForPhotonCloud,
149
150         EmailAlreadyRegistered,
151
152         SetupPhotonCloud,
153
154         SetupSelfHosted
155     }
156
157     
private GUIState guiState = GUIState.Uninitialized;
158
159     
private bool isSetupWizard = false;
160
161     
bool open = false;
162
163     
private PhotonSetupStates photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
164
165     
private static double lastWarning = 0;
166
167     
private static bool postCompileActionsDone;
168
169
170     
private string photonAddress = "127.0.0.1"; // custom server
171
172     
private int photonPort = 5055;
173
174     
private ConnectionProtocol photonProtocol;
175
176
177     
private string emailAddress = string.Empty;
178
179     
private string cloudAppId = string.Empty;
180
181     
private static bool dontCheckPunSetupField;
182
183     
private static Texture2D WizardIcon;
184
185     
protected static Type WindowType = typeof(PhotonEditor);
186
187     
private static readonly string[] CloudServerRegionNames;
188     
private static CloudRegionCode selectedRegion;
189     
private bool helpRegion;
190
191     
private static bool isPunPlus;
192     
private static bool androidLibExists;
193     
private static bool iphoneLibExists;
194
195     ///
<summary>
196     ///
Can be used to (temporarily) disable the checks for PUN Setup and scene PhotonViews.
197     ///
This will prevent scene PhotonViews from being updated, so be careful.
198     ///
When you re-set this value, checks are used again and scene PhotonViews get IDs as needed.
199     ///
</summary>
200     
protected static bool dontCheckPunSetup
201     {
202         
get
203         {
204             
return dontCheckPunSetupField;
205         }
206         
set
207         {
208             
if (dontCheckPunSetupField != value)
209             {
210                 dontCheckPunSetupField =
value;
211             }
212         }
213     }
214
215     
static PhotonEditor()
216     {
217         EditorApplication.projectWindowChanged += EditorUpdate;
218         EditorApplication.hierarchyWindowChanged += EditorUpdate;
219         EditorApplication.playmodeStateChanged += PlaymodeStateChanged;
220         EditorApplication.update += OnUpdate;
221
222         WizardIcon = AssetDatabase.LoadAssetAtPath(
"Assets/Photon Unity Networking/photoncloud-icon.png", typeof(Texture2D)) as Texture2D;
223
224         
// to be used in toolbar, the enum needs conversion to string[] being done here, once.
225         Array enumValues = Enum.GetValues(
typeof(CloudRegionCode));
226         CloudServerRegionNames =
new string[enumValues.Length];
227         
for (int i = 0; i < CloudServerRegionNames.Length; i++)
228         {
229             CloudServerRegionNames[i] = enumValues.GetValue(i).ToString();
230             
if (CloudServerRegionNames[i].Equals("none"))
231             {
232                 CloudServerRegionNames[i] = PhotonEditor.CurrentLang.BestRegionLabel;
233             }
234         }
235
236         
// detect optional packages
237         PhotonEditor.CheckPunPlus();
238
239     }
240
241     
internal protected static bool CheckPunPlus()
242     {
243         androidLibExists = File.Exists(
"Assets/Plugins/Android/libPhotonSocketPlugin.so");
244         iphoneLibExists = File.Exists(
"Assets/Plugins/IPhone/libPhotonSocketPlugin.a");
245
246         isPunPlus = androidLibExists || iphoneLibExists;
247         
return isPunPlus;
248     }
249
250     
private static void ImportWin8Support()
251     {
252         
if (EditorApplication.isCompiling || EditorApplication.isPlayingOrWillChangePlaymode)
253         {
254             
return; // don't import while compiling
255         }
256
257         #
if UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_1 || UNITY_5_2
258         
const string win8Package = "Assets/Plugins/Photon3Unity3D-Win8.unitypackage";
259
260         
bool win8LibsExist = File.Exists("Assets/Plugins/WP8/Photon3Unity3D.dll") && File.Exists("Assets/Plugins/Metro/Photon3Unity3D.dll");
261         
if (!win8LibsExist && File.Exists(win8Package))
262         {
263             AssetDatabase.ImportPackage(win8Package,
false);
264         }
265         #endif
266     }
267
268     
[MenuItem("Window/Photon Unity Networking/Locate Settings Asset %#&p")]
269     
protected static void Inspect()
270     {
271         EditorGUIUtility.PingObject(PhotonNetwork.PhotonServerSettings);
272         Selection.activeObject = PhotonNetwork.PhotonServerSettings;
273     }
274
275     
[MenuItem("Window/Photon Unity Networking/PUN Wizard &p")]
276     
protected static void Init()
277     {
278         PhotonEditor win = GetWindow(WindowType,
false, CurrentLang.WindowTitle, true) as PhotonEditor;
279         win.InitPhotonSetupWindow();
280
281         win.isSetupWizard =
false;
282         win.SwitchMenuState(GUIState.Main);
283     }

284
285     ///
<summary>Creates an Editor window, showing the cloud-registration wizard for Photon (entry point to setup PUN).</summary>
286     
protected static void ShowRegistrationWizard()
287     {
288         PhotonEditor win = GetWindow(WindowType,
false, CurrentLang.WindowTitle, true) as PhotonEditor;
289         win.isSetupWizard =
true;
290         win.InitPhotonSetupWindow();
291     }

292
293     ///
<summary>Re-initializes the Photon Setup window and shows one of three states: register cloud, setup cloud, setup self-hosted.</summary>
294     
protected void InitPhotonSetupWindow()
295     {
296         
this.minSize = MinSize;
297
298         
this.SwitchMenuState(GUIState.Setup);
299         
this.ReApplySettingsToWindow();
300
301         
switch (PhotonEditor.Current.HostType)
302         {
303             
case ServerSettings.HostingOption.PhotonCloud:
304             
case ServerSettings.HostingOption.BestRegion:
305                 
this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
306                 
break;
307             
case ServerSettings.HostingOption.SelfHosted:
308                 
this.photonSetupState = PhotonSetupStates.SetupSelfHosted;
309                 
break;
310             
case ServerSettings.HostingOption.NotSet:
311             
default:
312                 
this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
313                 
break;
314         }
315     }
316
317     
// called 100 times / sec
318     
private static void OnUpdate()
319     {
320         
// after a compile, check RPCs to create a cache-list
321         
if (!postCompileActionsDone && !EditorApplication.isCompiling && !EditorApplication.isPlayingOrWillChangePlaymode && PhotonEditor.Current != null)
322         {
323             #
if UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_1 || UNITY_5_2
324             
if (EditorApplication.isUpdating) return;
325             #endif
326
327             PhotonEditor.UpdateRpcList();
328             postCompileActionsDone =
true; // on compile, this falls back to false (without actively doing anything)
329             
330             #
if UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_1 || UNITY_5_2
331             PhotonEditor.ImportWin8Support();
332             #endif
333         }
334     }
335
336     
// called in editor, opens wizard for initial setup, keeps scene PhotonViews up to date and closes connections when compiling (to avoid issues)
337     
private static void EditorUpdate()
338     {
339         
if (dontCheckPunSetup || PhotonEditor.Current == null)
340         {
341             
return;
342         }
343
344         
// serverSetting is null when the file gets deleted. otherwise, the wizard should only run once and only if hosting option is not (yet) set
345         
if (!PhotonEditor.Current.DisableAutoOpenWizard && PhotonEditor.Current.HostType == ServerSettings.HostingOption.NotSet)
346         {
347             ShowRegistrationWizard();
348         }
349
350         
// Workaround for TCP crash. Plus this surpresses any other recompile errors.
351         
if (EditorApplication.isCompiling)
352         {
353             
if (PhotonNetwork.connected)
354             {
355                 
if (lastWarning > EditorApplication.timeSinceStartup - 3)
356                 {
357                     
// Prevent error spam
358                     Debug.LogWarning(CurrentLang.WarningPhotonDisconnect);
359                     lastWarning = EditorApplication.timeSinceStartup;
360                 }
361
362                 PhotonNetwork.Disconnect();
363             }
364         }
365     }
366
367     
// called in editor on change of play-mode (used to show a message popup that connection settings are incomplete)
368     
private static void PlaymodeStateChanged()
369     {
370         
if (dontCheckPunSetup || EditorApplication.isPlaying || !EditorApplication.isPlayingOrWillChangePlaymode)
371         {
372             
return;
373         }
374
375         
if (PhotonEditor.Current.HostType == ServerSettings.HostingOption.NotSet)
376         {
377             EditorUtility.DisplayDialog(CurrentLang.SetupWizardWarningTitle, CurrentLang.SetupWizardWarningMessage, CurrentLang.OkButton);
378         }
379     }
380
381     
private void SwitchMenuState(GUIState newState)
382     {
383         
this.guiState = newState;
384         
if (this.isSetupWizard && newState != GUIState.Setup)
385         {
386             
this.Close();
387         }
388     }
389
390     
protected virtual void OnGUI()
391     {
392         PhotonSetupStates oldGuiState =
this.photonSetupState; // used to fix an annoying Editor input field issue: wont refresh until focus is changed.
393
394         GUI.SetNextControlName(
"");
395         
this.scrollPos = GUILayout.BeginScrollView(this.scrollPos);
396
397         
if (this.guiState == GUIState.Uninitialized)
398         {
399             
this.ReApplySettingsToWindow();
400             
this.guiState = (PhotonEditor.Current.HostType == ServerSettings.HostingOption.NotSet) ? GUIState.Setup : GUIState.Main;
401         }
402
403         
if (this.guiState == GUIState.Main)
404         {
405             
this.OnGuiMainWizard();
406         }
407         
else
408         {
409             
this.OnGuiRegisterCloudApp();
410         }
411
412         GUILayout.EndScrollView();
413
414         
if (oldGuiState != this.photonSetupState)
415         {
416             GUI.FocusControl(
"");
417         }
418     }
419
420     
protected virtual void OnGuiRegisterCloudApp()
421     {
422         GUI.skin.label.wordWrap =
true;
423         
if (!this.isSetupWizard)
424         {
425             GUILayout.BeginHorizontal();
426             GUILayout.FlexibleSpace();
427             
if (GUILayout.Button(CurrentLang.MainMenuButton, GUILayout.ExpandWidth(false)))
428             {
429                 
this.SwitchMenuState(GUIState.Main);
430             }
431
432             GUILayout.EndHorizontal();
433
434             GUILayout.Space(
15);
435         }
436
437         
if (this.photonSetupState == PhotonSetupStates.RegisterForPhotonCloud)
438         {
439             GUI.skin.label.fontStyle = FontStyle.Bold;
440             GUILayout.Label(CurrentLang.ConnectButton);
441             EditorGUILayout.Separator();
442             GUI.skin.label.fontStyle = FontStyle.Normal;
443
444             GUILayout.Label(CurrentLang.UsePhotonLabel);
445             EditorGUILayout.Separator();
446             
this.emailAddress = EditorGUILayout.TextField(CurrentLang.EmailLabel, this.emailAddress);
447
448             
if (GUILayout.Button(CurrentLang.SendButton))
449             {
450                 GUIUtility.keyboardControl =
0;
451                 
this.RegisterWithEmail(this.emailAddress);
452             }
453
454             GUILayout.Space(
20);
455
456
457             GUILayout.Label(CurrentLang.SignedUpAlreadyLabel);
458             
if (GUILayout.Button(CurrentLang.SetupButton))
459             {
460                 
this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
461             }
462             EditorGUILayout.Separator();
463
464
465             GUILayout.Label(CurrentLang.RegisterByWebsiteLabel);
466             
if (GUILayout.Button(CurrentLang.AccountWebsiteButton))
467             {
468                 EditorUtility.OpenWithDefaultApp(UrlAccountPage + Uri.EscapeUriString(
this.emailAddress));
469             }
470
471             EditorGUILayout.Separator();
472
473             GUILayout.Label(CurrentLang.SelfHostLabel);
474
475             
if (GUILayout.Button(CurrentLang.SelfHostSettingsButton))
476             {
477                 
this.photonSetupState = PhotonSetupStates.SetupSelfHosted;
478             }
479
480             GUILayout.FlexibleSpace();
481
482
483             
if (!InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.Android) || !InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.iOS))
484             {
485                 GUILayout.Label(CurrentLang.MobileExportNoteLabel);
486             }
487             EditorGUILayout.Separator();
488         }
489         
else if (this.photonSetupState == PhotonSetupStates.EmailAlreadyRegistered)
490         {
491             GUI.skin.label.fontStyle = FontStyle.Bold;
492             GUILayout.Label(CurrentLang.OopsLabel);
493             GUI.skin.label.fontStyle = FontStyle.Normal;
494
495             GUILayout.Label(CurrentLang.EmailInUseLabel);
496
497             
if (GUILayout.Button(CurrentLang.SeeMyAccountPageButton))
498             {
499                 EditorUtility.OpenWithDefaultApp(UrlCloudDashboard + Uri.EscapeUriString(
this.emailAddress));
500             }
501
502             EditorGUILayout.Separator();
503
504             GUILayout.Label(CurrentLang.KnownAppIdLabel);
505             GUILayout.BeginHorizontal();
506             
if (GUILayout.Button(CurrentLang.CancelButton))
507             {
508                 
this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
509             }
510
511             
if (GUILayout.Button(CurrentLang.SetupButton))
512             {
513                 
this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
514             }
515
516             GUILayout.EndHorizontal();
517         }
518         
else if (this.photonSetupState == PhotonSetupStates.SetupPhotonCloud)
519         {
520             
// cloud setup
521             GUI.skin.label.fontStyle = FontStyle.Bold;
522             GUILayout.Label(CurrentLang.PhotonCloudConnect);
523             GUI.skin.label.fontStyle = FontStyle.Normal;
524
525             EditorGUILayout.Separator();
526             
this.OnGuiSetupCloudAppId();
527             
this.OnGuiCompareAndHelpOptions();
528         }
529         
else if (this.photonSetupState == PhotonSetupStates.SetupSelfHosted)
530         {
531             
// self-hosting setup
532             GUI.skin.label.fontStyle = FontStyle.Bold;
533             GUILayout.Label(CurrentLang.SetupOwnHostLabel);
534             GUI.skin.label.fontStyle = FontStyle.Normal;
535
536             EditorGUILayout.Separator();
537
538             
this.OnGuiSetupSelfhosting();
539             
this.OnGuiCompareAndHelpOptions();
540         }
541     }
542
543     
protected virtual void OnGuiMainWizard()
544     {
545         GUILayout.BeginHorizontal();
546         GUILayout.FlexibleSpace();
547         GUILayout.Label(WizardIcon);
548         GUILayout.FlexibleSpace();
549         GUILayout.EndHorizontal();
550
551         EditorGUILayout.Separator();
552
553         GUILayout.Label(CurrentLang.PUNWizardLabel, EditorStyles.boldLabel);
554         
if (isPunPlus)
555         {
556             GUILayout.Label(CurrentLang.MobilePunPlusExportNoteLabel);
557         }
558         
else if (!InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.Android) || !InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.iOS))
559         {
560             GUILayout.Label(CurrentLang.MobileExportNoteLabel);
561         }
562         EditorGUILayout.Separator();
563
564
565         
// settings button
566         GUILayout.BeginHorizontal();
567         GUILayout.Label(CurrentLang.SettingsButton, EditorStyles.boldLabel, GUILayout.Width(
100));
568         
if (GUILayout.Button(new GUIContent(CurrentLang.SetupButton, CurrentLang.SetupServerCloudLabel)))
569         {
570             
this.InitPhotonSetupWindow();
571         }
572
573         GUILayout.EndHorizontal();
574         EditorGUILayout.Separator();
575
576
577         
// find / select settings asset
578         GUILayout.BeginHorizontal();
579         GUILayout.Label(CurrentLang.SettingsFileLabel, EditorStyles.boldLabel, GUILayout.Width(
100));
580         
if (GUILayout.Button(new GUIContent(CurrentLang.LocateSettingsButton, CurrentLang.SettingsHighlightLabel)))
581         {
582             EditorGUIUtility.PingObject(PhotonEditor.Current);
583         }
584
585         GUILayout.EndHorizontal();
586
587
588         GUILayout.FlexibleSpace();
589
590         
// converter
591         GUILayout.BeginHorizontal();
592         GUILayout.Label(CurrentLang.ConverterLabel, EditorStyles.boldLabel, GUILayout.Width(
100));
593         
if (GUILayout.Button(new GUIContent(CurrentLang.StartButton, CurrentLang.UNtoPUNLabel)))
594         {
595             PhotonConverter.RunConversion();
596         }
597
598         GUILayout.EndHorizontal();
599         EditorGUILayout.Separator();
600
601
602         
// documentation
603         GUILayout.BeginHorizontal();
604         GUILayout.Label(CurrentLang.DocumentationLabel, EditorStyles.boldLabel, GUILayout.Width(
100));
605         GUILayout.BeginVertical();
606         
if (GUILayout.Button(new GUIContent(CurrentLang.OpenPDFText, CurrentLang.OpenPDFTooltip)))
607         {
608             EditorUtility.OpenWithDefaultApp(DocumentationLocation);
609         }
610
611         
if (GUILayout.Button(new GUIContent(CurrentLang.OpenDevNetText, CurrentLang.OpenDevNetTooltip)))
612         {
613             EditorUtility.OpenWithDefaultApp(UrlDevNet);
614         }
615
616         
if (GUILayout.Button(new GUIContent(CurrentLang.OpenCloudDashboardText, CurrentLang.OpenCloudDashboardTooltip)))
617         {
618             EditorUtility.OpenWithDefaultApp(UrlCloudDashboard + Uri.EscapeUriString(
this.emailAddress));
619         }
620
621         
if (GUILayout.Button(new GUIContent(CurrentLang.OpenForumText, CurrentLang.OpenForumTooltip)))
622         {
623             EditorUtility.OpenWithDefaultApp(UrlForum);
624         }
625
626         GUILayout.EndVertical();
627         GUILayout.EndHorizontal();
628     }
629
630     
protected virtual void OnGuiCompareAndHelpOptions()
631     {
632         GUILayout.FlexibleSpace();
633
634         GUILayout.Label(CurrentLang.QuestionsLabel);
635         
if (GUILayout.Button(CurrentLang.SeeForumButton))
636         {
637             Application.OpenURL(UrlForum);
638         }
639
640         
if (photonSetupState != PhotonSetupStates.SetupSelfHosted)
641         {
642             
if (GUILayout.Button(CurrentLang.OpenDashboardButton))
643             {
644                 EditorUtility.OpenWithDefaultApp(UrlCloudDashboard + Uri.EscapeUriString(
this.emailAddress));
645             }
646         }
647     }
648
649     
protected virtual void OnGuiSetupCloudAppId()
650     {
651         GUILayout.Label(CurrentLang.AppIdLabel);
652
653         GUILayout.BeginHorizontal();
654         
this.cloudAppId = EditorGUILayout.TextField(this.cloudAppId);
655
656         open = GUILayout.Toggle(open, PhotonGUI.HelpIcon, GUIStyle.none, GUILayout.ExpandWidth(
false));
657
658         GUILayout.EndHorizontal();
659
660         
if (open) GUILayout.Label(CurrentLang.AppIdInfoLabel);
661
662
663
664         EditorGUILayout.Separator();
665
666         GUILayout.Label(CurrentLang.CloudRegionLabel);
667
668         GUILayout.BeginHorizontal();
669         
int toolbarValue = GUILayout.Toolbar((int)selectedRegion, CloudServerRegionNames); // the enum CloudRegionCode is converted into a string[] in init (toolbar can't use enum)
670         helpRegion = GUILayout.Toggle( helpRegion, PhotonGUI.HelpIcon, GUIStyle.none, GUILayout.ExpandWidth(
false ) );
671         GUILayout.EndHorizontal();
672
673
674         
if (helpRegion) GUILayout.Label(CurrentLang.RegionalServersInfo);
675         PhotonEditor.selectedRegion = (CloudRegionCode)toolbarValue;
676
677         EditorGUILayout.Separator();
678
679         GUILayout.BeginHorizontal();
680         
if (GUILayout.Button(CurrentLang.CancelButton))
681         {
682             GUIUtility.keyboardControl =
0;
683             
this.ReApplySettingsToWindow();
684         }
685
686
687
688         
if (GUILayout.Button(CurrentLang.SaveButton))
689         {
690             GUIUtility.keyboardControl =
0;
691             
this.cloudAppId = this.cloudAppId.Trim();
692             PhotonEditor.Current.UseCloud(
this.cloudAppId);
693
694             PhotonEditor.Current.PreferredRegion = PhotonEditor.selectedRegion;
695             PhotonEditor.Current.HostType = (PhotonEditor.Current.PreferredRegion == CloudRegionCode.none)
696                                                 ? ServerSettings.HostingOption.BestRegion
697                                                 : ServerSettings.HostingOption.PhotonCloud;
698             PhotonEditor.Save();
699
700             Inspect();
701             EditorUtility.DisplayDialog(CurrentLang.SettingsSavedTitle, CurrentLang.SettingsSavedMessage, CurrentLang.OkButton);
702         }
703
704         GUILayout.EndHorizontal();
705
706
707
708         GUILayout.Space(
20);
709
710         GUILayout.Label(CurrentLang.SetupOwnServerLabel);
711
712         
if (GUILayout.Button(CurrentLang.SelfHostSettingsButton))
713         {
714             
//this.photonAddress = ServerSettings.DefaultServerAddress;
715             
//this.photonPort = ServerSettings.DefaultMasterPort;
716             
this.photonSetupState = PhotonSetupStates.SetupSelfHosted;
717         }
718
719         EditorGUILayout.Separator();
720         GUILayout.Label(CurrentLang.OwnHostCloudCompareLabel);
721         
if (GUILayout.Button(CurrentLang.ComparisonPageButton))
722         {
723             Application.OpenURL(UrlCompare);
724         }
725     }
726
727     
protected virtual void OnGuiSetupSelfhosting()
728     {
729         GUILayout.Label(CurrentLang.YourPhotonServerLabel);
730
731         
this.photonAddress = EditorGUILayout.TextField(CurrentLang.AddressIPLabel, this.photonAddress);
732         
this.photonPort = EditorGUILayout.IntField(CurrentLang.PortLabel, this.photonPort);
733         
this.photonProtocol = (ConnectionProtocol)EditorGUILayout.EnumPopup("Protocol", this.photonProtocol);
734         EditorGUILayout.Separator();
735
736         GUILayout.BeginHorizontal();
737         
if (GUILayout.Button(CurrentLang.CancelButton))
738         {
739             GUIUtility.keyboardControl =
0;
740             
this.ReApplySettingsToWindow();
741         }
742
743         
if (GUILayout.Button(CurrentLang.SaveButton))
744         {
745             GUIUtility.keyboardControl =
0;
746
747             PhotonEditor.Current.UseMyServer(
this.photonAddress, this.photonPort, null);
748             PhotonEditor.Current.Protocol =
this.photonProtocol;
749             PhotonEditor.Save();
750
751             Inspect();
752             EditorUtility.DisplayDialog(CurrentLang.SettingsSavedTitle, CurrentLang.SettingsSavedMessage, CurrentLang.OkButton);
753         }
754
755         GUILayout.EndHorizontal();
756
757
758         GUILayout.Space(
20);
759
760
761         
// license
762         GUILayout.BeginHorizontal();
763         GUILayout.Label(CurrentLang.LicensesLabel, EditorStyles.boldLabel, GUILayout.Width(
100));
764
765         
if (GUILayout.Button(new GUIContent(CurrentLang.LicenseDownloadText, CurrentLang.LicenseDownloadTooltip)))
766         {
767             EditorUtility.OpenWithDefaultApp(UrlFreeLicense);
768         }
769
770         GUILayout.EndHorizontal();
771
772
773         GUILayout.Space(
20);
774
775
776         GUILayout.Label(CurrentLang.TryPhotonAppLabel);
777
778         
if (GUILayout.Button(CurrentLang.GetCloudAppButton))
779         {
780             
this.cloudAppId = string.Empty;
781             
this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
782         }
783
784         EditorGUILayout.Separator();
785         GUILayout.Label(CurrentLang.OwnHostCloudCompareLabel);
786         
if (GUILayout.Button(CurrentLang.ComparisonPageButton))
787         {
788             Application.OpenURL(UrlCompare);
789         }
790     }
791
792     
protected virtual void RegisterWithEmail(string email)
793     {
794         EditorUtility.DisplayProgressBar(CurrentLang.ConnectionTitle, CurrentLang.ConnectionInfo,
0.5f);
795         
var client = new AccountService();
796         client.RegisterByEmail(email, RegisterOrigin);
// this is the synchronous variant using the static RegisterOrigin. "result" is in the client
797
798         EditorUtility.ClearProgressBar();
799         
if (client.ReturnCode == 0)
800         {
801             PhotonEditor.Current.UseCloud(client.AppId,
0);
802             PhotonEditor.Save();
803             
this.ReApplySettingsToWindow();
804             
this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
805         }
806         
else
807         {
808             
if (client.Message.Contains(CurrentLang.EmailInUseLabel))
809             {
810                 
this.photonSetupState = PhotonSetupStates.EmailAlreadyRegistered;
811             }
812             
else
813             {
814                 EditorUtility.DisplayDialog(CurrentLang.ErrorTextTitle, client.Message, CurrentLang.OkButton);
815                 
// Debug.Log(client.Exception);
816                 
this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
817             }
818         }
819     }
820
821     
#region SettingsFileHandling
822
823     
private static ServerSettings currentSettings;
824     
private Vector2 MinSize = new Vector2(350, 400);
825
826     
public static ServerSettings Current
827     {
828         
get
829         {
830             
if (currentSettings == null)
831             {
832                 
// find out if ServerSettings can be instantiated (existing script check)
833                 ScriptableObject serverSettingTest = CreateInstance(
"ServerSettings");
834                 
if (serverSettingTest == null)
835                 {
836                     Debug.LogError(CurrentLang.ServerSettingsMissingLabel);
837                     
return null;
838                 }
839                 DestroyImmediate(serverSettingTest);
840
841                 
// try to load settings from file
842                 ReLoadCurrentSettings();
843
844                 
// if still not loaded, create one
845                 
if (currentSettings == null)
846                 {
847                     
string settingsPath = Path.GetDirectoryName(PhotonNetwork.serverSettingsAssetPath);
848                     
if (!Directory.Exists(settingsPath))
849                     {
850                         Directory.CreateDirectory(settingsPath);
851                         AssetDatabase.ImportAsset(settingsPath);
852                     }
853
854                     currentSettings = (ServerSettings)ScriptableObject.CreateInstance(
"ServerSettings");
855                     
if (currentSettings != null)
856                     {
857                         AssetDatabase.CreateAsset(currentSettings, PhotonNetwork.serverSettingsAssetPath);
858                     }
859                     
else
860                     {
861                         Debug.LogError(CurrentLang.ServerSettingsMissingLabel);
862                     }
863                 }
864
865                 
// settings were loaded or created. set this editor's initial selected region now (will be changed in GUI)
866                 
if (currentSettings != null)
867                 {
868                     selectedRegion = currentSettings.PreferredRegion;
869                 }
870             }
871
872             
return currentSettings;
873         }
874
875         
protected set
876         {
877             currentSettings =
value;
878         }
879     }
880
881     
public static void Save()
882     {
883         EditorUtility.SetDirty(PhotonEditor.Current);
884     }
885
886     
public static void ReLoadCurrentSettings()
887     {
888         
// this now warns developers if there are more than one settings files in resources folders. first will be used.
889         UnityEngine.Object[] settingFiles = Resources.LoadAll(PhotonNetwork.serverSettingsAssetFile,
typeof(ServerSettings));
890         
if (settingFiles != null && settingFiles.Length > 0)
891         {
892             PhotonEditor.Current = (ServerSettings)settingFiles[
0];
893
894             
if (settingFiles.Length > 1)
895             {
896                 Debug.LogWarning(CurrentLang.MoreThanOneLabel + PhotonNetwork.serverSettingsAssetFile + CurrentLang.FilesInResourceFolderLabel + AssetDatabase.GetAssetPath(PhotonEditor.Current));
897             }
898         }
899     }
900
901     
protected void ReApplySettingsToWindow()
902     {
903         
this.cloudAppId = string.IsNullOrEmpty(PhotonEditor.Current.AppID) ? string.Empty : PhotonEditor.Current.AppID;
904         
this.photonAddress = string.IsNullOrEmpty(PhotonEditor.Current.ServerAddress) ? string.Empty : PhotonEditor.Current.ServerAddress;
905         
this.photonPort = PhotonEditor.Current.ServerPort;
906         
this.photonProtocol = PhotonEditor.Current.Protocol;
907     }
908
909     
public static void UpdateRpcList()
910     {
911         List<
string> additionalRpcs = new List<string>();
912         HashSet<
string> currentRpcs = new HashSet<string>();
913
914         
var types = GetAllSubTypesInScripts(typeof(MonoBehaviour));
915
916         
foreach (var mono in types)
917         {
918             MethodInfo[] methods = mono.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
919
920             
foreach (MethodInfo method in methods)
921             {
922                 
if (method.IsDefined(typeof(UnityEngine.RPC), false))
923                 {
924                     currentRpcs.Add(method.Name);
925
926                     
if (!additionalRpcs.Contains(method.Name) && !PhotonEditor.Current.RpcList.Contains(method.Name))
927                     {
928                         additionalRpcs.Add(method.Name);
929                     }
930                 }
931             }
932         }
933
934         
if (additionalRpcs.Count > 0)
935         {
936             
// LIMITS RPC COUNT
937             
if (additionalRpcs.Count + PhotonEditor.Current.RpcList.Count >= byte.MaxValue)
938             {
939                 
if (currentRpcs.Count <= byte.MaxValue)
940                 {
941                     
bool clearList = EditorUtility.DisplayDialog(CurrentLang.IncorrectRPCListTitle, CurrentLang.IncorrectRPCListLabel, CurrentLang.RemoveOutdatedRPCsLabel, CurrentLang.CancelButton);
942                     
if (clearList)
943                     {
944                         PhotonEditor.Current.RpcList.Clear();
945                         PhotonEditor.Current.RpcList.AddRange(currentRpcs);
946                     }
947                     
else
948                     {
949                         
return;
950                     }
951                 }
952                 
else
953                 {
954                     EditorUtility.DisplayDialog(CurrentLang.FullRPCListTitle, CurrentLang.FullRPCListLabel, CurrentLang.SkipRPCListUpdateLabel);
955                     
return;
956                 }
957             }
958
959             additionalRpcs.Sort();
960             PhotonEditor.Current.RpcList.AddRange(additionalRpcs);
961             EditorUtility.SetDirty(PhotonEditor.Current);
962         }
963     }
964
965     
public static void ClearRpcList()
966     {
967         
bool clearList = EditorUtility.DisplayDialog(CurrentLang.PUNNameReplaceTitle, CurrentLang.PUNNameReplaceLabel, CurrentLang.RPCListCleared, CurrentLang.CancelButton);
968         
if (clearList)
969         {
970             PhotonEditor.Current.RpcList.Clear();
971             Debug.LogWarning(CurrentLang.ServerSettingsCleanedWarning);
972         }
973     }
974
975     
public static System.Type[] GetAllSubTypesInScripts(System.Type aBaseClass)
976     {
977         
var result = new System.Collections.Generic.List<System.Type>();
978         System.Reflection.Assembly[] AS = System.AppDomain.CurrentDomain.GetAssemblies();
979         
foreach (var A in AS)
980         {
981             
// this skips all but the Unity-scripted assemblies for RPC-list creation. You could remove this to search all assemblies in project
982             
if (!A.FullName.StartsWith("Assembly-"))
983             {
984                 
// Debug.Log("Skipping Assembly: " + A);
985                 
continue;
986             }
987
988             
//Debug.Log("Assembly: " + A.FullName);
989             System.Type[] types = A.GetTypes();
990             
foreach (var T in types)
991             {
992                 
if (T.IsSubclassOf(aBaseClass))
993                     result.Add(T);
994             }
995         }
996         
return result.ToArray();
997     }
998
999     
#endregion
1000 }


----------------------------------------------------------------------------

PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH

MenuItems and in-Editor scripts for PhotonNetwork.

developer@exitgames.com

----------------------------------------------------------------------------

protected static string UrlFreeLicense = "https:www.exitgames.comenOnPremiseDashboard";

protected static string UrlDevNet = "http:doc.exitgames.comenpuncurrentgetting-started";

protected static string UrlForum = "http:forum.exitgames.com";

protected static string UrlCompare = "http:doc.exitgames.comenrealtimecurrentgetting-startedonpremise-or-saas";

protected static string UrlHowToSetup = "http:doc.exitgames.comenonpremisecurrentgetting-startedphoton-server-in-5min";

protected static string UrlAppIDExplained = "http:doc.exitgames.comenrealtimecurrentgetting-startedobtain-your-app-id";

protected static string UrlAccountPage = "https:www.exitgames.comAccountSignIn?email="; opened in browser

protected static string UrlCloudDashboard = "https:cloud.exitgames.comDashboard?email=";

private string photonAddress = "127.0.0.1"; custom server

Can be used to (temporarily) disable the checks for PUN Setup and scene PhotonViews.

This will prevent scene PhotonViews from being updated, so be careful.

When you re-set this value, checks are used again and scene PhotonViews get IDs as needed.

to be used in toolbar, the enum needs conversion to string[] being done here, once.

detect optional packages

return; don't import while compiling

Creates an Editor window, showing the cloud-registration wizard for Photon (entry point to setup PUN).

Re-initializes the Photon Setup window and shows one of three states: register cloud, setup cloud, setup self-hosted.

called 100 times sec

after a compile, check RPCs to create a cache-list

postCompileActionsDone = true; on compile, this falls back to false (without actively doing anything)

called in editor, opens wizard for initial setup, keeps scene PhotonViews up to date and closes connections when compiling (to avoid issues)

serverSetting is null when the file gets deleted. otherwise, the wizard should only run once and only if hosting option is not (yet) set

Workaround for TCP crash. Plus this surpresses any other recompile errors.

Prevent error spam

called in editor on change of play-mode (used to show a message popup that connection settings are incomplete)

PhotonSetupStates oldGuiState = this.photonSetupState; used to fix an annoying Editor input field issue: wont refresh until focus is changed.

cloud setup

self-hosting setup

settings button

find select settings asset

converter

documentation

int toolbarValue = GUILayout.Toolbar((int)selectedRegion, CloudServerRegionNames); the enum CloudRegionCode is converted into a string[] in init (toolbar can't use enum)

this.photonAddress = ServerSettings.DefaultServerAddress;

this.photonPort = ServerSettings.DefaultMasterPort;

license

client.RegisterByEmail(email, RegisterOrigin); this is the synchronous variant using the static RegisterOrigin. "result" is in the client

Debug.Log(client.Exception);

find out if ServerSettings can be instantiated (existing script check)

try to load settings from file

if still not loaded, create one

settings were loaded or created. set this editor's initial selected region now (will be changed in GUI)

this now warns developers if there are more than one settings files in resources folders. first will be used.

LIMITS RPC COUNT

this skips all but the Unity-scripted assemblies for RPC-list creation. You could remove this to search all assemblies in project

Debug.Log("Skipping Assembly: " + A);

Debug.Log("Assembly: " + A.FullName);




Trò chơi Tic-Tac-Toe, game đánh caro full source code 53.458 lượt xem

Gõ tìm kiếm nhanh...